# -*- coding: iso-8859-15 -*-
#
# LICENSE:
# 
# Copyright 2008 Håkan Lindqvist. All rights reserved.
# 
# Redistribution and use in source and binary forms, 
# with or without modification, are permitted provided 
# that the following conditions are met:
# 
#    1. Redistributions of source code must retain the 
#       above copyright notice, this list of conditions 
#       and the following disclaimer.
#    2. Redistributions in binary form must reproduce the 
#       above copyright notice, this list of conditions 
#       and the following disclaimer in the documentation 
#       and/or other materials provided with the distribution.
# 
# THIS SOFTWARE IS PROVIDED BY HÅKAN LINDQVIST ``AS IS'' 
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL HÅKAN LINDQVIST 
# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 
# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 
# DAMAGE.
# 

from adt.report.Report import Report

class HTMLReport(Report):
	"""Main ADT HTML report class. It simply collects entries as div tags
	   and provides a simple means to generate a resulting HTML document.
   	"""

	def __init__(self, out=None, titlePage=None, indexPage=None, contentPages=None):
		if not out:
			raise Exception("A HTML report must have a named target file.")
		self.__out      = out
		self.__story    = []

		# A list of files linked by the Report, such as images
		self.__linked   = []

		if not contentPages:
			raise Exception("The parameter 'contentPages' must be specified")

		if titlePage:
			self.append(titlePage)

		if indexPage:
			self.append(indexPage.makeIndex(contentPages.getIndexLinks()))

		self.append(contentPages)

	def getFiles(self):
		"""Return the link to the files used by this report."""
		files = [self.__out]
		files.extend(self.__linked)

		return files

	def append(self, item):
		""" Append a ReportPage to the Report """
		if isinstance(item, ReportContents):
			for x in item.get():
				self.__story.append(x)
		else:
			self.__story.append(item)
	
	def generateHTML(self):
		"""Concatenate the story to a HTML document, adding the
		   style and needed standard tags.
		"""
		top = """
		<html>
		<head>
		  <title> %s </title>
		  <style type="text/css">
		    html,body  { border:0px; margin:0px; padding:0px; }
		    body       { background: #dedede; border:0px; margin:10px; }

		    a:active   { color:black;   }
		    a:hover    { color:red;     }
		    a:link     { color:red;     }
		    a:visited  { color:black;   }

		    #Title     { background:#fefefe; color:red; border-width: 1px; border-bottom-style: solid; font-size: x-large; font-weight: bold; }
		    #Abstract  { background:#ffd;        }
		    #Abstract .title { font-weight:bold; }

			#Index           { background:#ffd;  }
			#Index .title    { font-weight:bold; }
			#Index .entries  { font-size:small; margin-left: 40px; }
		    #Index a:active  { color:black; }
		    #Index a:hover   { color:black; }
		    #Index a:link    { color:black; }
		    #Index a:visited { color:black; }

		    #content   { background:#fff; border:1px; border-top: 2px; border-bottom: 2px; border-style: solid; border-color:black; padding:10px; padding-bottom:0px; margin-bottom:0px; }
			#content .Heading1 { font-size: large;  font-weight:bold; }
			#content .Heading2 { font-size: normal; font-weight:bold; }
			#content .Heading3 { font-size: small;  font-weight:bold; font-style:italic; }

		    #Separator { color:#fefefe; }
		    #Separator hr { background:#ee0000; border:0px; color:#ee0000; height:1px; }
		  </style>
		</head>
		<body>
		<div id="content">
		""" % "Report"

		bottom = """
		</div>
		</body>
		</html>
		"""

		html = [top]

		html.extend(self.__story)
		html.append(bottom)

		return '\n'.join(html)

	def write(self, out=None):
		""" Write the report; if no output has been defined (i.e. is None),
		    the data will be written to stdout.
		"""
		if out:
			self.__out = out

		if not self.__out:
			self.__out = sys.stdout

		if isinstance(self.__out, str):
			self.__out = file(self.__out, "w")

		self.__out.write(self.generateHTML())

class ReportContents:
	"""Base class for ADT report contents, it is a simple place holder
	   for div tag sections.
	"""
	def __init__(self):
		self.index = []
		self.items = []

	def get(self):
		"""Get the div tags registered with this contents holder."""
		return self.items

	def add(self, item):
		"""Add an item to this holder. If a ReportContents instance, or rather
		   a subclass thereof, is added, the div tag items from that instance
		   will be fetched and added instead.
		"""
		if isinstance(item, ReportContents):
			for x in item.get():
				self.items.append(x)
		else:
			self.items.append(item)
	
	def addIndexLink(self, indexLink):
		self.index.append(indexLink)

	def getIndexLinks(self):
		return self.index

class ReportTitlePage(ReportContents):
	"""Report title page."""

	def __init__(self, title=None, titleColor=None, abstract=None):
		ReportContents.__init__(self)

		if not title:
			raise Exception("The 'title' parameter must contain a value.")

		title = """
		<div id="Title">
		  %s
		</div>
		""" % title

		self.add(title)

		if abstract:
			abstract = """
			<div id="Abstract">
			<p class="title">Abstract:</p>
			<p>
			  %s
			</p>
			</div>
			""" % abstract

			self.add(abstract)

		self.add(PageBreak())

class ReportIndex(ReportContents):
	"""Table of contents, it is only used as a marker to trigger the
	   actions needed to create the index.
	"""
	def makeIndex(self, links):
		"""Given a list of anchors, create a proper list
		   that can be used as an index.
		"""

		index = """
		<div id="Index">
		  <p class="title">Index:</p>
		  <p class="entries">
		    %s
		  </p>
		</div>
		""" % "<br/>".join(links)

		return index + str(PageBreak())

class ReportPages(ReportContents):
	"""Normal report pages."""
	def add(self, code, style='', index='#'):
		if isinstance(code, ReportContents):
			code = '\n'.join(code.get())
		else:
			code = """
			<div id="%s" class="%s">
			  %s
			</div>
			""" % (index, style, code)

		ReportContents.add(self, code)

		if style.startswith("Heading") and not index == "#":
			link = """
			<a href="#%s"> %s </a>
			""" % (index, index)

			self.addIndexLink(link)

class PageBreak(ReportContents):
	"""Emulate a page break by adding a horizontal line."""

	def __init__(self):
		ReportContents.__init__(self)

		separator = """
		<div id="Separator">
		  <hr/>
		</div>
		"""

		self.add(separator)

	def __str__(self):
		return self.get()[0]

# If used as a script, run a small test case
if __name__ == "__main__":
	title    = ReportTitlePage(title='Foo test report', abstract='A simple test report with an abstract that is only there to occupy some text.')
	index    = ReportIndex()
	contents = ReportPages()

	contents.add("<p> First1            </p>", style="Heading1", index="First1")
	contents.add("<p> bla bla bla       </p>", style="Normal")
	contents.add("<p> Second1           </p>", style="Heading2", index="Second1")
	contents.add("<p> bla bla bla       </p>", style="Normal")
	contents.add("<p> Third1            </p>", style="Heading3", index="Third1")
	contents.add("<p> bla bla bla       </p>", style="Normal")
	contents.add(PageBreak())
	contents.add("<p> First2            </p>", style="Heading1", index="First2")
	contents.add("<p> bla bla bla       </p>", style="Normal")
	contents.add("<p> Second2           </p>", style="Heading2", index="Second2")
	contents.add("<p> bla bla bla       </p>", style="Normal")

	HTMLReport(out='test.html', titlePage=title, indexPage=index, contentPages=contents).write()

